package testApplets;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Vector;



import marchingCubes.IsMCVertex;
import marchingCubes.MCube;
import marchingCubes.MCubeEngineLowMemory;

import peasy.PeasyCam;
import processing.core.PApplet;
import simpleGeom.Bounds3D;
import simpleGeom.Box3D;
import simpleGeom.DepthAnalyser3D;
import simpleGeom.Face3D;
import simpleGeom.Node;
import simpleGeom.SimpleObjLoaderStream;
import simpleGeom.SimpleTriangle;
import simpleGeom.TrianglePreCalc;
import simpleGeom.Vec3D;
import testApplets.MeshToSolid2.Cell;

public class OffestApplet extends PApplet{
	ArrayList<Node> nodes = new ArrayList<Node>();
	ArrayList<Face3D> faces = new ArrayList<Face3D>();
	Vector<SimpleTriangle> meFaces;
	Cell[][][] grid;
	Box3D b3d = new Bounds3D();
	String path="/Users/caad/Desktop/Archive/";
	String input=path+"form | 21-09-12 |Solid03CutSel.obj";
	String output=path+"testInside.obj";
	float dim=0.05113f;
	PeasyCam cam;
ScanLine[][] scans;
public void setup(){
	size(1024,768,P3D);
	loadObj(input);
	scanMesh();
	cam=new PeasyCam(this,b3d.getCenterX(),b3d.getCenterY(),b3d.getCenterZ(),400);
}

public void draw(){
	background(0);
	scale(100);
	stroke(255,0,0);
	for (int x=0;x<grid.length;x++){
		for (int y=0;y<grid[x].length;y++){
			Cell cell=grid[x][y][0];
			point(cell.x,cell.y,cell.z);
		}
	}
	stroke(255);
	//fill(255);
	for (int i=0;i<faces.size();i+=20){
		Face3D f=faces.get(i);
		f.display3D(g);
	}
	noFill();
	stroke(0,255,0);
	b3d.display3D(g);
	for (int x=0;x<scans.length;x++){
		for (int y=0;y<scans[x].length;y++){
			ScanLine sc=scans[x][y];
			for (int i=0;i<sc.values.size();i++){
				point(x*dim+b3d.x1,y*dim+b3d.y1,sc.values.get(i));
			}
		}
	}
	fill(255);
	for (int x=0;x<grid.length;x++){
		for (int y=0;y<grid[x].length;y++){
			for (int z=0;z<grid[x][y].length;z++){
				Cell cell=grid[x][y][z];
				if (cell.getValue()>0){
					pushMatrix();
					translate(cell.x,cell.y,cell.z);
					box(dim,dim,dim);
					popMatrix();
				}
			}
		}
	}
}

public void loadObj(String pathObjIn){
	SimpleObjLoaderStream stream = new SimpleObjLoaderStream();
	stream.init(pathObjIn);
	float[] vertex = stream.readVertex();
	while (vertex != null) {
		nodes.add(new Node(vertex[0], vertex[1], vertex[2]));
		vertex = stream.readVertex();
	}
	println("nodes: " + nodes.size());
	stream.close();
	stream.init(pathObjIn);
	int[] face = stream.readFace();
	while (face != null) {
		TrianglePreCalc f = new TrianglePreCalc(new Vec3D(),new Vec3D(),new Vec3D());
		if (face.length == 4) {
			f = new TrianglePreCalc(nodes.get(face[0] - 1),
					nodes.get(face[1] - 1), nodes.get(face[2] - 1));
			faces.add(f);
			f.init();
			f = new TrianglePreCalc(nodes.get(face[2] - 1),
					nodes.get(face[3] - 1), nodes.get(face[0] - 1));
			faces.add(f);

			for (int i = 0; i < face.length; i++) {
				Node n = nodes.get(face[i] - 1);
				n.setComment(1);
			}
			f.init();
		} else {
			f = new TrianglePreCalc(nodes.get(face[0] - 1),
					nodes.get(face[1] - 1), nodes.get(face[2] - 1));
			for (int i = 0; i < face.length; i++) {
				Node n = nodes.get(face[i] - 1);
				n.setComment(1);
			}
			faces.add(f);
			f.init();
		}
		face = stream.readFace();
	}
	ArrayList<Node> newNodes = new ArrayList<Node>();
	for (int i = 0; i < nodes.size(); i++) {
		Node n = nodes.get(i);
		if (n.getComment() == 1) {
			newNodes.add(n);
		}
	}
	b3d=new Bounds3D();
	
	((Bounds3D)b3d).addAll(nodes);
	 b3d=b3d.getOffsetBox(dim*2f);
	println("loaded");
}
public void scanMesh(){
	float sX=b3d.getX1();
	float sY=b3d.getY1();
	float sZ=b3d.getZ1();
	int nX=(int)(b3d.getDimX()/dim)+1;
	int nY=(int)(b3d.getDimY()/dim)+1;
	int nZ=(int)(b3d.getDimZ()/dim)+1;
	grid=new Cell[nX][nY][nZ];
	scans=new ScanLine[nX][nY];
	for (int x=0;x<nX;x++){
		for (int y=0;y<nY;y++){
			scans[x][y]=new ScanLine();
		}
	}
	for (int x=0;x<nX;x++){
		for (int y=0;y<nY;y++){
			for (int z=0;z<nZ;z++){
				float cX=x*dim+sX;
				float cY=y*dim+sY;
				float cZ=z*dim+sZ;
				Cell cell=new Cell(cX,cY,cZ);
				grid[x][y][z]=cell;
			}
		}
	}
	Vec3D ray=new Vec3D(0,0,1);
	for (int i=0;i<faces.size();i++){
		
		TrianglePreCalc f=(TrianglePreCalc) faces.get(i);
		Box3D b3d=f.getBounds3D();
		int x1=(int)((b3d.x1-sX)/dim)-1;
		int x2=(int)((b3d.x2-sX)/dim)+2;
		int y1=(int)((b3d.y1-sY)/dim)-1;
		int y2=(int)((b3d.y2-sY)/dim)+2;
		for (int x=x1;x<x2;x++){
			//println("x: "+x);
			for (int y=y1;y<y2;y++){
				Cell cell=grid[x][y][0];
				ScanLine scan=scans[x][y];
				//Vec3D v=f.intersect_RayTriangle2(cell, new Vec3D(cell.x,cell.y,cell.z+1));
				Vec3D v=null;
				if (v!=null){
					scan.values.add(new Float(v.z));
				}
				
			}
		}
	}
	float[][][]depth=new float[nX][nY][nZ];
	for (int x=0;x<nX;x++){
		for (int y=0;y<nY;y++){
			ScanLine scan=scans[x][y];
			if (scan.values.size()>0){
				Collections.sort(scan.values);
				for (int z=0;z<scan.values.size()-1;z+=2){
					float z1=scan.values.get(z);
					float z2=scan.values.get(z+1);
					int zK1=(int)((z1-sZ)/dim);
					int zK2=(int)((z2-sZ)/dim);
					for (int cZ=zK1;cZ<zK2;cZ++){
						depth[x][y][cZ]=10000000;
						/*Cell cell=grid[x][y][cZ];
						cell.setValue(1000000000);*/
					}
				}
			}
		}
	}
	DepthAnalyser3D da=new DepthAnalyser3D();
	da.calculateDepth(depth,1,1.41f,1.71f);
	depth=da.depth;
	for (int x=0;x<nX;x++){
		for (int y=0;y<nY;y++){
			for (int z=0;z<nZ;z++){
				Cell cell=grid[x][y][z];
				cell.setValue(depth[x][y][z]);
			}
		}
	}
	meFaces = MCubeEngineLowMemory.initCubesTest(grid,2f,null);
	
	println("start save");
	this.saveObjPrintwriter(output,meFaces);
	println("scanned");
}


public void saveObjPrintwriter(String file, Vector<SimpleTriangle> meFaces) {
	PrintWriter output = createWriter(file + ".obj");

	int idV = 1;
	Bounds3D meshBounds=new Bounds3D();
	for (int i = 0; i < meFaces.size(); i++) {
		SimpleTriangle f = meFaces.get(i);
		for (int j = 0; j < f.getNodesNum(); j++) {
			Vec3D n = (Vec3D) f.getNode(j);
			meshBounds.addPoint(n);
			if (n.getId() == 0) {
				n.setId(idV);
				idV++;
				output.println("v " + n.x + " " + n.y + " " + n.z);
			}
		}
	}
	
	output.println("g inside");
	for (int i = 0; i < meFaces.size(); i++) {
		SimpleTriangle f = meFaces.get(i);
		int[] ids = new int[f.getNodesNum()];
		String string = "f";
		
		for (int j = 0; j < f.getNodesNum(); j++) {
			Vec3D n = (Vec3D) f.getNode(j);
			string += " " + n.getId();
		}
		output.println(string);
	}
	
	output.flush(); // Writes the remaining data to the file
	output.close();
}
public class Cell  extends Vec3D implements IsMCVertex {
	
	float d = Float.MAX_VALUE;
	boolean inside;
	MCube cube;
	public Cell() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Cell(float x,float y,float z) {
		super(x,y,z);
	}

	public float getValue() {
		// TODO Auto-generated method stub
		return d;
	}

	public void setValue(double value) {
		// TODO Auto-generated method stub
		this.d = (float) value;
	}

	public MCube getCube() {
		// TODO Auto-generated method stub
		return cube;
	}

	public void setCube(MCube cube) {
		// TODO Auto-generated method stub
		this.cube = cube;
	}


	@Override
	public int getId() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void setId(int i) {
		// TODO Auto-generated method stub

	}
}
class ScanLine{
	Vector<Float>values=new Vector<Float>();
}
}
